﻿/********
* 
* 
*  Description:
*  Create By Kain at 4/6/2011 4:25:22 PM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/

#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Collections.Concurrent;
using Cherry.Agile.Framework;
using System.Text.RegularExpressions;
#endregion

namespace Cherry.Agile.ServiceModel.Runtime
{
    [ServiceBehavior(InstanceContextMode= InstanceContextMode.Single)]
    public sealed class ServiceConsole:IServiceConsole
    {
        static Lazy<List<ServicePackage>> _packages = new Lazy<List<ServicePackage>>(LoadPackages);
        static ConcurrentDictionary<int, List<ServiceInfo>> _services = new ConcurrentDictionary<int, List<ServiceInfo>>();
        static ConcurrentDictionary<int, ServiceRunner> _serviceRuners = new ConcurrentDictionary<int, ServiceRunner>();
        static object _sync = new object();

        ServerInfomation _serverInformation = new ServerInfomation() {
            Name = Config.RempServiceModelSection.Current.Service.Name,
            StateDate = DateTime.Now,
            Version = Config.RempServiceModelSection.Current.Service.Version,
            Type = Config.RempServiceModelSection.Current.Service.Usage
        };

        public IEnumerable<ServicePackageInfo> GetServicePackages()
        {
            return _packages.Value.Select(c=>new ServicePackageInfo(){ Id= c.Id, Name= c.Name} );
        }

        public IEnumerable<ServiceInfo> GetService(int packageId)
        {
            List<ServiceInfo> lst;
            if (!_services.TryGetValue(packageId, out lst))
            {
                var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
                if (package == null)
                    return null;
                var runner = GetServiceRuner(package);
                lst = runner.GetServicesInfo().ToList();
                //lst = RuntimeUnity.GetService(package).Select(c => c.Info).ToList();

                _services.TryAdd(packageId, lst);
            }
            return lst;
        }

        public void StartService(int packageId)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return;

            var runner = GetServiceRuner(package);
            if( runner.Unloaded)
                runner.Load();
            runner.Run(GetEventListener(), ServiceFilter.Empty);
        }

        public void StartService( int packageId, string sericeFullName)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return;
            var runner = GetServiceRuner(package);

            runner.Run(GetEventListener(), new SimpleNameFilter(sericeFullName));
        }

        public void StopService(int packageId)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return;

            var runner = GetServiceRuner(package);
            runner.Unload();
            //runner.Stop(GetEventListener(), ServiceFilter.Empty);
        }

        public void StopService(int packageId, string sericeFullName)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return;
            var runner = GetServiceRuner(package);

            runner.Stop(GetEventListener(), new SimpleNameFilter(sericeFullName));
        }

        public IEnumerable<ServiceInfo> GetServiceInfo(int packageId)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return null;

            var runner = GetServiceRuner(package);

            return runner.Info( ServiceFilter.Empty).ToList();
        }

        public IEnumerable<ServiceInfo> GetServiceInfo(int packageId, string sericeFullName)
        {
            var package = _packages.Value.FirstOrDefault(c => c.Id == packageId);
            if (package == null)
                return null;
            var runner = GetServiceRuner(package);

            return runner.Info(new SimpleNameFilter(sericeFullName));
        }

        public ServerInfomation GetServerState() {
            return _serverInformation;
        }

        #region private methods
        static List<ServicePackage> LoadPackages()
        {
            var values = RuntimeUnity.GetServicePackages(string.Empty);

            return values;
        }

        private ServiceRunner GetServiceRuner(ServicePackage package)
        {
            ServiceRunner runner;
            if (!_serviceRuners.TryGetValue(package.Id, out runner))
            {
                lock (_sync)
                {
                    runner = CreateServiceRuner(package);
                   
                    _serviceRuners.TryAdd(package.Id, runner);
                }
            }
            return runner;
        }

        private ServiceRunner CreateServiceRuner(ServicePackage package)
        {
            var runer = new ServiceRunner(package);
            runer.Load();
            return runer;
        }

        private IServiceFilter GetFilter(string[] serviceFullNames)
        {
            return new SimpleNameFilter(serviceFullNames);
        }

        static IEventListener _lisener = new EventListener();
        private IEventListener GetEventListener()
        {
            return _lisener;
        }
        #endregion

        #region static
        public static void Start() {
            
        }

        public static void Stop() {

        }

        static string GetAddress(string address) {
            var port = string.Empty;
            var reg = new Regex(@":\d+");
            var m = reg.Match(address);
            if (m.Success) {
                port = m.Value.TrimStart(':');
                return address.Replace(port, (port.ToInt() + 1000).ToString());
            } 

            throw new ArgumentException("the server address has not a valid port.");
        }
        #endregion
    }



}
